
from team import *
import random
import sys

class Game:

  # This is the constructor method for game.
  #
  # **Arguments**
  #
  # *homename* - string containing the name of the home team
  #
  # *homefile* - string containing the name of a datafile
  #
  # *awayname* - string containing the name of the home team
  #
  # *awayfile* - string containing the name of a datafile
  #
  # **returns** none
  def __init__(self,whererun,homename,homefile,awayname,awayfile):

    # This tells you whether the game is run 
    # as a cgi script or as main
    self.whererun = whererun

    # A game contains two teams
    self.hometeam = Team(self.whererun,homename,homefile)
    self.awayteam = Team(self.whererun,awayname,awayfile)

    # The game must know its score
    self.homescore = 0
    self.awayscore = 0

    # The game must know what inning it is
    self.inning = 1

    # The game has some hard-wired probabilities
        # For now, assume a double play occurs 20% of the time
        # This is a random choice, and should be evaluated
    self.dp_chance = 0.30
        # For now, assume a runner goes 1st to 3rd 50% of the time
        # on a single and scores on any other hit
        # This is a random choice, and should be evaluated
    self.makes_to_third = 0.5
        # For now, assume a runner scores from second 90% of the time
        # on a single and 100% of the time on any other hit
        # This is a random choice, and should be evaluated
    self.score_from_second = 0.8

    self.other_pitcher_effect = 1.0

    # The game must know who is on each base
    self.firstbase= ""
    self.secondbase= ""
    self.thirdbase= ""
    # homebase needs to possibly hold more than one person
    # for instance on a homerun
    self.homebase= [] 


  # This is the funtion called to start a game
  #
  # **Arguments** none
  #
  # **returns** none
  def start(self):

    # The inning counter is too big by one, so decrement
    print 5*"\n"
    print "Welcome to PyBaseball!"
    print "This game is between",self.hometeam.name,"and",self.awayteam.name,"."
    print 5*"\n"
    if self.whererun=="main":
      dummy = raw_input("Ready to begin? ")

  # This is the funtion called to end a game
  #
  # **Arguments** none
  #
  # **returns** none
  def end(self):

    # The inning counter is too big by one, so decrement
    self.inning=self.inning-1
    # Give each team its score 
    self.awayteam.score=self.awayscore
    self.hometeam.score=self.homescore

    # Print out a standard baseball linescore
    # 
    # Make heavy use of 'ljust' from string module to left-justify
    print 
    print 
    print 
    print "FINAL SCORE IN",self.inning,"INNINGS:",self.hometeam.name,"-", self.homescore," ",self.awayteam.name,"-", self.awayscore
    print 
    print 
    print ljust("",15),
    for j in range(1,self.inning+1):
     inn = str(j)
     # Only print the last digit of an inning
     # for formatting reasons (e.g. 10 = "0", 11="1", etc)
     print inn[len(inn)-1],

    print ljust("",1),
    print "R  H  E"

    print (15+2*self.inning+10)*"="
   
    # print team stats
    for team in [self.awayteam,self.hometeam]:
      print ljust(team.name,15),
      for k in range(0,self.inning):
        print team.scorebyinning[k],
      print ljust("",1),
      print ljust(str(team.score),2),
      print ljust(str(team.hits),2),
      print ljust(str(team.errs),2)

  # This is the function that plays a game
  #
  # **Arguments** none
  #
  # **return** none
  def play(self):
  
    # Some print strings to print results
    pa_printres=["made an out.","hit a single.","hit a double.","hit a triple.","hit a homerun!"]

    # play an inning if not up to 9 innings yet or score is tied
    while self.inning < 10 or self.homescore == self.awayscore:

      # Do some intoductory stuff, like print an intro
      self.InningIntro()

      # Loop over both teams, away team batting first
      for upteam in [self.awayteam,self.hometeam]:

        # Check if home team doesn't need to bat in the bottom of the
        # last inning
        # If the home team has already won, just set outs=3
        if upteam==self.hometeam and self.homescore > self.awayscore and self.inning > 8:
          outs=3
        else:
          outs=0
          print "The "+upteam.name+" are batting."

        # Loop until there are three outs
        while outs < 3:
          # Figure out who's up
          whosup = upteam.players[upteam.upnext]

          # Print current batter to screen
          print "  "+whosup.name,

          # What does the batter do?
          batter_result=self.PlateAppearance(outs,whosup)

          # Print result of that plate appearance
          if batter_result["whichbase"] and not batter_result["hit"]:
            print "drew a walk."
          elif batter_result["double_play"]:
            print "grounded into a double play."
          else:
            print pa_printres[batter_result["whichbase"]]

          # advance the runners, if necessary
          self.Advancerunners(whosup,batter_result,outs)

          # OK, done with that batter
          # Update inning
          outs=outs+self.Updateinning(batter_result)
          # Check if the hometeam has won...if so, set outs=3 to end game
          # Update team stats if necessary and get new batter
          self.Updateteam(upteam,batter_result)
          if upteam==self.hometeam and self.homescore+upteam.scorebyinning[self.inning-1] > self.awayscore and self.inning > 8:
            outs=3

          # If there are less than three outs, print out what
          # is going on (who's on what base, etc)
          if outs < 3:
            self.Printstatus(outs)
          else: 
            print "    There are three outs."

        # There are three outs, so call a function to finish a half-inning
        self.Teamisdone(upteam)
      # Inning is over, so increment and do again
      self.InningFinish()
  
  # This function finishes a half-inning
  #
  # **Arguments**
  #
  # *upteam* - the team that just batted
  #
  # **returns** none
  def PlateAppearance(self,outs,player):

    # initialize these to zero, since that will happen the most
    double_play=0
    whichbase=0
    hit=0

    # Pick a random number to see if that batter gets on base
    ob = random.random()
    # Pick a random number to see if that batter gets on base
    isahit = random.random()
    # Pick a random number to see what base (if any)
    whb = random.random()
    # Pick a random number to see if its a DP
    dp = random.random()

    # Compare to batting average
    if ob < self.other_pitcher_effect*player.oba:
      whichbase=1
      if isahit < player.h/(player.h+player.bb):
        hit=1 
        # is it a HR?
        if whb < player.hr/player.h:
          whichbase=4
        # is it a 3B?
        elif whb < (player.hr+player.threeb)/player.h:
          whichbase=3
        # is it a 2B?
        elif whb < (player.hr+player.threeb+player.twob)/player.h:
          whichbase=2
    # if it's an out, check if it's a DP
    # for now, hardwire the chances of a DP at 25%
    elif outs < 2 and self.firstbase and dp < self.dp_chance:
      double_play=1

    return({"hit":hit,"whichbase":whichbase,"double_play":double_play})


  # This function finishes a half-inning
  #
  # **Arguments**
  #
  # *upteam* - the team that just batted
  #
  # **returns** none
  def Teamisdone(self,upteam):

    # update the score for the appropriate team
    if upteam == self.hometeam:
      self.homescore=self.homescore+upteam.scorebyinning[self.inning-1]
    else:
      self.awayscore=self.awayscore+upteam.scorebyinning[self.inning-1]

    # clear the bases
    self.Clearbases()
  
  # This function finishes an inning
  #
  # **Arguments** - none
  #
  # **returns** none
  def InningFinish(self):

    # increment counter
    self.inning=self.inning+1

    # pause to let player see the results
    # only if the program is being run from prompt
    if self.whererun=="main":
      dummy = raw_input("Ready to continue? ")

  
  # This function starts an inning
  #
  # **Arguments** - none
  #
  # **returns** none
  def InningIntro(self):

    # Print some header stuff
    print 2*"\n"
    print "INNING "+str(self.inning)
    tmpstr=self.hometeam.name+":"+ str(self.homescore)+" "+self.awayteam.name+":"+ str(self.awayscore)
    print ljust(tmpstr,30)
    print 30*"="
    print 

    # Append another inning on each teams running score
    self.hometeam.scorebyinning.append(0)
    self.awayteam.scorebyinning.append(0)

  # This function clears the bases (when a half-inning is done)
  #
  # **Arguments** - none
  #
  # **returns** none
  def Clearbases(self):
    self.firstbase=""
    self.secondbase=""
    self.thirdbase=""
    self.homebase=[]
  
  # This function advances base runners
  #
  # **Arguments**
  #
  # *player* - the player that just got a hit
  #
  # **returns** none
  def Advancerunners(self,player,pa_result,outs):
    #
    # First, the logic associated with a hit
    if pa_result["hit"]:
      # You've got to work backwards from third or a runner keeps advancing
      #
      # For now, assume a runner scores from third on any hit
      if self.thirdbase:
        self.homebase.append(self.thirdbase)
        self.thirdbase=""
      if self.secondbase:
        if pa_result["whichbase"]>1 or random.random() < self.score_from_second:
          self.homebase.append(self.secondbase)
        else:
          self.thirdbase=self.secondbase
        self.secondbase=""
      if self.firstbase:
        if pa_result["whichbase"] >1:
          self.homebase.append(self.firstbase)
        # Make sure no one's on third too
        elif random.random() < self.makes_to_third and not self.thirdbase:
          self.thirdbase=self.firstbase
        else:
          self.secondbase=self.firstbase
        self.firstbase=""
     
      #Put the runner on base now that everyone's advanced
      if pa_result["whichbase"]==1:
        self.firstbase=player.name
      elif pa_result["whichbase"]==2:
        self.secondbase=player.name
      elif pa_result["whichbase"]==3:
        self.thirdbase=player.name
      elif pa_result["whichbase"]==4:
        self.homebase.append(player.name)
    # Now, the logic of a walk
    elif pa_result["whichbase"] and not pa_result["hit"]:
      if self.thirdbase and self.secondbase and self.firstbase:
        self.homebase.append(self.thirdbase)
      if self.secondbase and self.firstbase:
        self.thirdbase=self.secondbase
      if self.firstbase:
        self.secondbase=self.firstbase
      self.firstbase=player.name

    # Finally, a double play
    elif pa_result["double_play"]:
      if self.thirdbase and outs == 0:
        self.homebase.append(self.thirdbase)
      if self.secondbase:
        self.thirdbase=self.secondbase
        self.secondbase=""
      self.firstbase=""
      
  # This function updates a team with each new batter
  #
  # **Arguments**
  #
  # *upteam* - the team that is batting
  #
  # **returns** none
  def Updateinning(self,pa):
    if pa["whichbase"]:
      return 0
    elif pa["double_play"]:
      return 2
    else:
      return 1
      
  # This function updates a team with each new batter
  #
  # **Arguments**
  #
  # *upteam* - the team that is batting
  #
  # **returns** none
  def Updateteam(self,upteam,pa_res):
    # If a hit, update hit total
    if pa_res["hit"]:
      upteam.hits=upteam.hits+1
    # If someone made it home, update score, print a note and empty homebase
    if self.homebase:
      score=len(self.homebase)
      upteam.scorebyinning[self.inning-1]=upteam.scorebyinning[self.inning-1]+score
      for name in self.homebase:
        print "     **",strip(name),"scored **"
      self.homebase=[]
    # Get a new batter
    upteam.Newbatter()
        
  # This function prints out who's on what base
  #
  # **Arguments** - none
  #
  # **returns** none
  def Printstatus(self,outs):
    # print number of outs
    if outs==0:
      print "    There are no outs."
    if outs==1:
      print "    There is one out."
    if outs==2:
      print "    There are two outs."

    # print who's on base
    if self.firstbase:
      print "   ",self.firstbase,"is on first."
    if self.secondbase:
      print "   ",self.secondbase,"is on second."
    if self.thirdbase:
      print "   ",self.thirdbase,"is on third."
      
